﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using libzkfpcsharp;
using System.Runtime.InteropServices;
using System.IO;

namespace KeyperDev
{
    public delegate void iniSuccessDelegate();
    public delegate void regstCapturedDelegate(int i);
    public delegate void matchCapturedDelegate(int i);
    public class Fingerprint
    {
        public int useFP = 0; //0表示不使用指纹，1表示使用
        public byte[] RegAlready = new byte[2048];



        private IntPtr mDevHandle = IntPtr.Zero;
        private IntPtr mDBHandle = IntPtr.Zero;
        private IntPtr FormHandle = IntPtr.Zero;
        private byte[][] RegTmps = new byte[3][];
        private byte[] RegTmp = new byte[2048];
        private byte[] CapTmp = new byte[2048];
        private int cbCapTmp = 2048;
        private int cbRegTmp = 0;
        private int iFid = 1;
        private int regstCount = 0;
        private bool bIsTimeToDie = false;
        private bool IsRegister = false;
        private bool bIdentify = true;
        private byte[] FPBuffer;
        private int RegisterCount = 0;
        private const int REGISTER_FINGER_COUNT = 3;
        private int mfpWidth = 0;
        private int mfpHeight = 0;

        const int MESSAGE_CAPTURED_OK = 0x0400 + 6;

        private int whatToDoFlag = 0;  //0表示什么也不干，1表示注册，2表示验证
        

        private Thread iniFpDeviceThread;
        
        private Thread captureThread;
        public iniSuccessDelegate iniSuccess;
        public regstCapturedDelegate regstCaptured;
        public matchCapturedDelegate matchCaptured;
        private string fingerFileName = "";

        public Fingerprint() 
        {
            
        }
        public Fingerprint(string str1,string str2) 
        {
            fingerFileName = str1 + @"\" + str2;
            FileStream fs = new FileStream(fingerFileName, FileMode.OpenOrCreate);
            BinaryReader br = new BinaryReader(fs);
            try
            {
                int i = br.ReadInt32();
                if (i == 1)
                {
                    useFP = 1;                       //这里有漏洞，删除文件可绕过指纹，应使用非对称防修改
                    RegAlready = br.ReadBytes(2048);
                }
                else
                {
                    useFP = 0;
                }
                br.Close();
                fs.Close();
            }
            catch (Exception e) 
            {
                useFP = 0;
                br.Close();
                fs.Close();
            }
            

           
        }
        public void iniFpDevice() 
        {
            iniFpDeviceThread = new Thread(iniFpDeviceThreadMethod);
            iniFpDeviceThread.Start();
        }
        public void stopini() 
        {
            try
            {
                iniFpDeviceThread.Abort();

            }
            catch (Exception e) 
            {
            
            }
        
        }
        public void stopDevice() 
        {
            whatToDoFlag = 0;
            regstCount = 0;
            bIsTimeToDie = true;
            inRunning = false;
            Thread.Sleep(1000);
            try
            {
                zkfp2.Terminate();
                //zkfp2.CloseDevice(mDevHandle);
            }
            catch (Exception e) 
            {
            
            }
          
        }
        private bool inRunning = true;
        private void iniFpDeviceThreadMethod()
        {
            
            int ret = zkfperrdef.ZKFP_ERR_OK;
            inRunning = true;
            while (inRunning == true)
            {
                try
                {
                    ret = zkfp2.Init();
                    if (ret == zkfperrdef.ZKFP_ERR_OK || ret == 1)
                    {

                        if (IntPtr.Zero == (mDevHandle = zkfp2.OpenDevice(0)))
                        {
                            continue;
                        }
                        if (IntPtr.Zero == (mDBHandle = zkfp2.DBInit()))
                        {
                            zkfp2.CloseDevice(mDevHandle);
                            mDevHandle = IntPtr.Zero;
                            continue;
                        }
                        RegisterCount = 0;
                        cbRegTmp = 0;
                        iFid = 1;
                        for (int i = 0; i < 3; i++)
                        {
                            RegTmps[i] = new byte[2048];
                        }
                        byte[] paramValue = new byte[4];
                        int size = 4;
                        zkfp2.GetParameters(mDevHandle, 1, paramValue, ref size);
                        zkfp2.ByteArray2Int(paramValue, ref mfpWidth);
                        size = 4;
                        zkfp2.GetParameters(mDevHandle, 2, paramValue, ref size);
                        zkfp2.ByteArray2Int(paramValue, ref mfpHeight);
                        FPBuffer = new byte[mfpWidth * mfpHeight];

                        captureThread = new Thread(captureThreadMethod);
                        captureThread.IsBackground = true;
                        captureThread.Start();
                        bIsTimeToDie = false;

                        iniSuccess();
                        return;
                    }
                    else
                    {
                        Thread.Sleep(500);
                    }
                }
                catch (Exception e)
                {


                }
               
            }                                  
        }

        public void regstFinger() 
        {
            whatToDoFlag = 1;
        }
        public void stopregstFinger()
        {
            whatToDoFlag = 0;
        
        }
        public void cmpFinger()
        {
            whatToDoFlag = 2;
        }
        public void closeFingerService() 
        {
            FileStream fs = new FileStream(fingerFileName, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(0);
            
            bw.Close();
            fs.Close();
        
        }

        private void captureThreadMethod()
        {

            while (!bIsTimeToDie)
            {
                cbCapTmp = 2048;
                int ret = zkfp2.AcquireFingerprint(mDevHandle, FPBuffer, CapTmp, ref cbCapTmp);

                if (ret == zkfp.ZKFP_ERR_OK)
                {
                    solveCaptured(MESSAGE_CAPTURED_OK);

                }
                Thread.Sleep(200);
            }
        }

        private void solveCaptured(int MESSAGE_CAPTURED)
        {
            switch (MESSAGE_CAPTURED) 
            {
                case MESSAGE_CAPTURED_OK:
                    if (whatToDoFlag == 0)
                    {
                        return;
                    }
                    if (whatToDoFlag == 1)
                    {
                        solveRegst();
                        return;
                    }
                    else if (whatToDoFlag == 2)
                    {
                        solveCmp();
                        return;
                    }


                    return;
                default:
                    return;
            }

          
        }
        public void writefinger() 
        {
            FileStream fs = new FileStream(fingerFileName, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(1);
            bw.Write(RegAlready);
            bw.Close();
            fs.Close();
        
        }
        private void solveRegst() 
        {
            /*
              MemoryStream ms = new MemoryStream();
              BitmapFormat.GetBitmap(FPBuffer, mfpWidth, mfpHeight, ref ms);
              Bitmap bmp = new Bitmap(ms);
             */
            int ret = zkfp.ZKFP_ERR_OK;
            int fid = 0, score = 0;
            iFid = 1;
            ret = zkfp2.DBIdentify(mDBHandle, CapTmp, ref fid, ref score);
            if (zkfp.ZKFP_ERR_OK == ret)
            {
                //textRes.Text = "This finger was already register by " + fid + "!";
                RegisterCount = 0;
                regstCaptured(4);  //This finger was already registered

                return;
            }
            if (RegisterCount > 0 && zkfp2.DBMatch(mDBHandle, CapTmp, RegTmps[RegisterCount - 1]) <= 0)
            {
                 // textRes.Text = "Please press the same finger 3 times for the enrollment";
                RegisterCount = 0;
                regstCaptured(3);

                return;
            }
            Array.Copy(CapTmp, RegTmps[RegisterCount], cbCapTmp);
            String strBase64 = zkfp2.BlobToBase64(CapTmp, cbCapTmp);
            byte[] blob = zkfp2.Base64ToBlob(strBase64);
            RegisterCount++;
            if (RegisterCount >= REGISTER_FINGER_COUNT)
            {
                RegisterCount = 0;
                zkfp2.DBClear(mDBHandle);
                if (zkfp.ZKFP_ERR_OK == (ret = zkfp2.DBMerge(mDBHandle, RegTmps[0], RegTmps[1], RegTmps[2], RegTmp, ref cbRegTmp)))
                {
                    iFid++;
                    RegTmp.CopyTo(RegAlready,0);
                    FileStream fs = new FileStream(fingerFileName, FileMode.Create);
                    BinaryWriter bw = new BinaryWriter(fs);
                    bw.Write(1);
                    bw.Write(RegAlready);
                    bw.Close();
                    fs.Close();


                    //textRes.Text = "enroll succ";
                    regstCaptured(0);
               
                }
                else
                {
                    //textRes.Text = "enroll fail, error code=" + ret;
                    regstCaptured(-1);
                }
                IsRegister = false;
                return;
            }
            else
            {
                //textRes.Text = "You need to press the " + (REGISTER_FINGER_COUNT - RegisterCount) + " times fingerprint";
                regstCaptured(REGISTER_FINGER_COUNT - RegisterCount);
            
            }


        }
        private void solveCmp()
        {
            int ret = zkfp2.DBMatch(mDBHandle, CapTmp, RegAlready);
            if (0 < ret)
            {
                //textRes.Text = "Match finger succ, score=" + ret + "!";
                matchCaptured(ret);
                return;
            }
            else
            {
                matchCaptured(ret);
                //textRes.Text = "Match finger fail, ret= " + ret;
                return;
            }
        }

        












    }
}
